import database
import requests
import json
import update_logic
from twisted.python import log
commands = {}



def error_sender(severity):
    def fail(reason,**kw):
        dic = {"what":severity,"msg":reason}
        dic.update(kw)
        return dic
    return fail

fail = error_sender("fail")
error = error_sender("error")
server_error = error_sender("server error")

def cmd(func):
    " Registers a function as a command " 
    commands[func.func_name.upper()]=func
    return func    

def do(player, action):
    try:
        js = json.loads(action)
        if not type(js) is list:
            js = [js]
        for req in js:
            cmd = req.pop('what')
            assert cmd.upper() in commands, ("No such command:{}"
            " please refer to"
            " https://code.google.com/p/caster/wiki/casterJsonProtocol"
            .format(cmd))
            commands[cmd.upper()](player, **req)
    except AssertionError, e:
        log.err()
        player.send(error(repr(e), action = action))
    except Exception, e:
        log.err()
        player.send(server_error(repr(e), action = action))
        
    
############ COMMANDS: ###############

@cmd
def LOGIN(player, login, passw):
    "LOGIN <login> <passwd> returns creature list\n"
    
    send = player.send
    if player.login:
        send(error("Already logged in"))
        return
    
    with database.Handler() as h:
        creatures = h.login(login, passw)
        if creatures == None:
            send(fail("Login and/or pass are wrong"))
            return
        elif not creatures:
            send(fail("Login {} has no creatures".format(login)))
            return
        
        player.login = login
        player.creatures = cr = {str(c.id):c for c in creatures}
        players = player.factory.players
        if login in players:
            player.disconnect("logged in from another connection")
            return
        player.factory.players[login]=player
        send({"what":"login","creatures":[c.short_info for c in cr.values()]})

@cmd 
def JOIN(player, crid):

    with database.Handler() as h:
        player.creature = h.session.merge(player.creatures[crid])
        if not player.creature.cell:
            requests.ENTER(player, 1)
        else:
            player.loc_id = player.creature.cell.loc_id
            @update_logic.locking("get env", False, id = player.loc_id)
            def send(lock):
                update_logic.send_environment(player, player.loc_id, h)
    
@cmd
def REQUEST(player,**kwargs):
    if player.committed:
        player.send(error("Already committed"))
        return
    type = kwargs.pop('type') #@ReservedAssignment
    assert type.upper() in requests.requests, "No such request:"+str(type)
    requests.requests[type.upper()](player, **kwargs)

@cmd 
def EXIT(player, msg=None):
    player.disconnect()
        
